package com.wangyadong.hobby.schedule.jobtask.jvm.check;

import org.aspectj.asm.IProgramElement;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.util.ElementScanner8;
import javax.tools.Diagnostic;
import java.util.EnumSet;
import java.util.Set;

/**
 * <p>
 *
 * @author <714037465@qq.com>
 * @since 2018/11/2915:15
 **/
@SupportedAnnotationTypes("*")
public class NameCheckProcessor extends AbstractProcessor {
    private NameCheck nameCheck;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.nameCheck = new NameCheck(processingEnv);
    }

    protected NameCheckProcessor() {
        super();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        if (!roundEnv.processingOver()) {
            for (Element element : roundEnv.getRootElements()) {
                nameCheck.check(element);
            }
        }
        return false;
    }


    static class NameCheck {
        Messager messager = null;
        public NameCheckScanner nameCheckScanner;

        private NameCheck(ProcessingEnvironment processingEnv) {
            messager = processingEnv.getMessager();
            nameCheckScanner = new NameCheckScanner(processingEnv);

        }

        public void check(Element element) {
            nameCheckScanner.scan(element);
        }

        static class NameCheckScanner extends ElementScanner8<Void, Void> {
            Messager messager = null;

            public NameCheckScanner(ProcessingEnvironment processingEnvironment) {
                messager = processingEnvironment.getMessager();
            }

            /**
             * 此方法用于检查java类
             *
             * @param e
             * @param aVoid
             * @return
             */
            @Override
            public Void visitType(TypeElement e, Void aVoid) {
                scan(e.getTypeParameters(), aVoid);
                super.visitType(e, aVoid);
                return null;
            }

            private void checkCamelCase(Element element, boolean initialCaps) {
                String name = element.getSimpleName().toString();
                boolean previousUpper = false;
                boolean conventional = true;
                int firstCodePoint = name.codePointAt(0);
                if (Character.isUpperCase(firstCodePoint)) {
                    previousUpper = true;
                    if (!initialCaps) {
                        messager.printMessage(Diagnostic.Kind.WARNING, "名称:" + name +
                                "应当以小写开头", element);
                    }
                } else if (Character.isLowerCase(firstCodePoint)) {
                    if (initialCaps) {
                        messager.printMessage(Diagnostic.Kind.WARNING, "名称:" + name + "应当大写开头", element);
                    }
                } else {
                    conventional = false;
                }

                if (conventional) {
                    int cp = firstCodePoint;
                    for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {
                        cp = name.codePointAt(i);
                        if (Character.isUpperCase(cp)) {
                            if (previousUpper) {
                                conventional = false;
                                break;
                            }
                            previousUpper = true;
                        } else {
                            previousUpper = false;
                        }
                    }
                }
                if (!conventional) {
                    messager.printMessage(Diagnostic.Kind.WARNING, "名称:" +
                            name + " 应当符合驼式命名法（Camel Case Names） ", element);
                }
            }

            /**
             * 检查方法名称是否合法
             *
             * @param e
             * @param aVoid
             * @return
             */
            @Override
            public Void visitExecutable(ExecutableElement e, Void aVoid) {
                if (e.getKind() == ElementKind.METHOD) {
                    Name simpleName = e.getSimpleName();
                    if (simpleName.contentEquals(e.getEnclosingElement().getSimpleName())) {
                        messager.printMessage(Diagnostic.Kind.WARNING, "名称：" +
                                simpleName + "不应当与类名重复", e);
                    }
                }
                super.visitExecutable(e, aVoid);
                return null;
            }

            @Override
            public Void visitVariable(VariableElement e, Void aVoid) {
                if (e.getKind() == ElementKind.ENUM_CONSTANT || e.getConstantValue() != null || heuristicallyConstant(e))
                    super.visitVariable(e, aVoid);
                return null;
            }

            /**
             * 判断 是不是常量
             *
             * @param e
             * @return
             */
            private boolean heuristicallyConstant(VariableElement e) {
                if (e.getEnclosingElement().getKind() == ElementKind.INTERFACE) {
                    return true;
                } else if (e.getKind() == ElementKind.FIELD && e.getModifiers().containsAll(
                        EnumSet.of(Modifier.FINAL,
                                Modifier.STATIC,
                                Modifier.PUBLIC

                        ))) {
                    return true;
                }
                return false;
            }
        }
    }


}
